﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BbsbWebService.Classes;
using BbsbWebService.Enums;
using System.Runtime.Serialization;
using BbsbWebService.Repositories;
using System.Xml.Linq;

namespace BbsbWebService.Tasks
{
    [DataContract]
    [KnownType(typeof(ScheduledTask))]
    [KnownType(typeof(OneOffTask))]
    [KnownType(typeof(RecurringTask))]
    public abstract class BaseTask : BaseItem
    {
        #region Constructors

        public BaseTask() { }

        public BaseTask(DateTime dateTime)
        {
            NextAlarm = dateTime;
        }

        public BaseTask(XElement element)
        {
            NextAlarm = element.GetChildValueFromElement<DateTime?>("NextAlarm");
            Id = element.GetChildValueFromElement<Guid>("Id");
            Name = element.GetChildValueFromElement<string>("Name");
            PowerOption = (PowerOption)element.GetChildValueFromElement<int>("PowerOption");
            Guid item = element.GetChildValueFromElement<Guid>("Item");
            Disabled = element.GetChildValueFromElement<bool>("Disabled");
            Item = RepositoryInstances.GetItem(item);
        }

        #endregion

        #region DataMembers

        [DataMember(IsRequired = true)]
        public PowerOption PowerOption { get; set; }

        [DataMember(IsRequired = true)]
        public Guid ItemId
        {
            get
            {
                return Item.Id;
            }
            set
            {
                if (value != Guid.Empty)
                {
                    Item = RepositoryInstances.GetItem(value);
                }
            }
        }

        [DataMember(EmitDefaultValue=false)]
        public bool Disabled { get; set; }

        [DataMember(IsRequired = true)]
        public DateTime? NextAlarm { get; set; }

        #endregion

        #region Public Properties

        public BaseItem Item { get; set; }

        public string Description
        {
            get
            {
                string value = string.Empty;
                if (NextAlarm.HasValue)
                {
                    value = string.Format("Turns {0} '{1}' at {2}{3}", PowerOption, Item.Name, NextAlarm.Value.ToShortTimeString(), AdditionalDesctiption);
                }
                return value;
            }
        }

        #endregion

        #region Abstract Properties/Methods

        protected abstract string AdditionalDesctiption { get; }

        protected abstract IEnumerable<XElement> GetRestAsXElement();

        protected abstract void SetNextAlarm();

        #endregion

        public XElement GetAsXElement()
        {
            XElement element = new XElement(this.GetType().ToString(),
                new XElement("Name", Name),
                new XElement("Id", Id),
                new XElement("NextAlarm", NextAlarm),
                new XElement("PowerOption", (int)PowerOption),
                new XElement("Item", Item.Id),
                new XElement("Disabled", Disabled),
                GetRestAsXElement());

            return element;
        }

        public void Execute()
        {
            if (!Disabled)
            {
                RepositoryInstances.SendPower(Item.Id, PowerOption);
            }

            SetNextAlarmMain();
        }

        protected void SetNextAlarmMain()
        {
            DateTime now = DateTime.Now;
            while (NextAlarm.HasValue &&
                   NextAlarm.Value < now)
            {
                SetNextAlarm();
            }
        }

        protected override void Validate(ref ValidationState state)
        {
            base.Validate(ref state);

            if (!NextAlarm.HasValue)
                state.AddError("Task date/time cannot be null");

            if (Item == null)
                state.AddError("Task item cannot be null");
        }
    }
}
